#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

// 游戏窗口尺寸
#define WIDTH 32
#define HEIGHT 16
// 蛇的最大长度
#define MAX_LENGTH 100

// 方向枚举
typedef enum {
    STOP,
    LEFT,
    RIGHT,
    UP,
    DOWN
} Direction;

// 蛇结构体
typedef struct {
    int x[MAX_LENGTH];
    int y[MAX_LENGTH];
    int length;
    Direction dir;
} Snake;

// 食物结构体
typedef struct {
    int x;
    int y;
} Food;

// 全局变量用于局部刷新
int last_tail_x = 0, last_tail_y = 0;
int first_frame = 1;
Food old_food = {0};

// 函数声明
void init_game(Snake *snake, Food *food);
void init_map(Snake *snake, Food *food, int high_score);
void update_snake(Snake *snake, int growing);
void update_food(Food *food);
void update_score(int score, int high_score, int speed_level);

void move_snake(Snake *snake);
void generate_food(Snake *snake, Food *food);
void change_direction(Snake *snake, int key);
int check_collision(Snake *snake);
void save_score(int score);
int load_score();
void welcome_to_game();
void print_snake();
void print_GAMEOVER();
void score_and_tips(int score, int high_score, int speed_level);
void explanation();
void print_tips(); // 新增函数声明

// 新增函数声明
int biteself(Snake *snake);
void cantcrosswall(Snake *snake, int *game_over);
void speedup(int *sleeptime, int *speed_level);
void speeddown(int *sleeptime, int *speed_level);
void snakemove(Snake *snake);
void keyboardControl(Snake *snake, int *sleeptime, int *score, int *paused, int *speed_level);
void game_over_screen(int score, int high_score, int *restart);

// 控制台光标移动函数
void gotoxy(SHORT tempx, SHORT tempy) {
    COORD pos = {tempx, tempy};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

// 新增：打印操作提示
void print_tips() {
    gotoxy(0, HEIGHT + 3);
    printf("使用WASD键来控制蛇的方向.");
    gotoxy(0, HEIGHT + 4);
    printf("按Esc键 暂停/恢复 游戏.");
    gotoxy(0, HEIGHT + 5);
    printf("按 上/下箭头键 进行加/减速.");
}

int main() {
    int restart = 1;
    
    while (restart) {
        restart = 0;
        Snake snake;
        Food food;
        int game_over = 0;
        int score = 0;
        int high_score = load_score();
        int sleeptime = 180;
        int paused = 0;
        int speed_level = 1; // 初始速度等级为1
        int grow = 0;

        system("cls"); // 清空屏幕
        first_frame = 1; // 新增重置代码：确保每次新游戏都会初始化地图
        welcome_to_game();
        init_game(&snake, &food);

        while (!game_over) {
            if (!paused) {
                if (first_frame) {
                    init_map(&snake, &food, high_score);
                } else {
                    // 记录移动前的尾部位置
                    last_tail_x = snake.x[snake.length - 1];
                    last_tail_y = snake.y[snake.length - 1];
                    
                    move_snake(&snake);
                    
                    // 检查是否吃到食物
                    if (snake.x[0] == food.x && snake.y[0] == food.y) {
                        score += speed_level;
                        if (score > high_score) {
                            high_score = score;
                            save_score(high_score);
                        }
                        generate_food(&snake, &food);
                        grow = 1;
                        
                    } else {
                        grow = 0;
                    }

                    // 增长处理
                    if (grow) {
                        if (snake.length < MAX_LENGTH) {
                            // 增加新的一节在尾部
                            snake.x[snake.length] = last_tail_x;
                            snake.y[snake.length] = last_tail_y;
                            snake.length++;
                        }
                    }

                    update_snake(&snake, grow);
                    update_food(&food);
                    update_score(score, high_score, speed_level);

                    if (check_collision(&snake)) {
                        game_over = 1;
                    }
                }

                keyboardControl(&snake, &sleeptime, &score, &paused, &speed_level);
                Sleep(sleeptime);
                first_frame = 0;
                old_food = food;
            } else {
                // 显示暂停信息
                gotoxy(0, HEIGHT + 3);
                printf("          暂停中...           ");
                // 只处理ESC键
                if (_kbhit()) {
                    int key = _getch();
                    if (key == 27) { // ESC键恢复
                        paused = 0;
                        // 清除暂停信息
                        gotoxy(0, HEIGHT + 3);
                        printf("                              ");
                        // 恢复操作提示
                        print_tips();
                    }
                }
            }
        }

        // 游戏失败界面
        game_over_screen(score, high_score, &restart);
    }

    return 0;
}

void init_game(Snake *snake, Food *food) {
    snake->length = 3;
    snake->x[0] = WIDTH / 2;
    snake->y[0] = HEIGHT / 2;
    snake->x[1] = WIDTH / 2 - 1;
    snake->y[1] = HEIGHT / 2;
    snake->x[2] = WIDTH / 2 - 2;
    snake->y[2] = HEIGHT / 2;
    snake->dir = RIGHT;  // 初始方向改为向右

    generate_food(snake, food);
}

void init_map(Snake *snake, Food *food, int high_score) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    // 清空屏幕以避免残留
    system("cls");

    // 绘制边界
    for (int i = 0; i < WIDTH; i++) {
        gotoxy(i, 0); printf("#");
        gotoxy(i, HEIGHT - 1); printf("#");
    }
    for (int i = 0; i < HEIGHT; i++) {
        gotoxy(0, i); printf("#");
        gotoxy(WIDTH - 1, i); printf("#");
    }

    // 显示初始食物
    gotoxy(food->x, food->y);
    SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN);
    printf("$");
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

    // 显示初始蛇身
    for (int i = 0; i < snake->length; i++) {
        gotoxy(snake->x[i], snake->y[i]);
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN);
        printf("O");
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    }

    // 记录当前食物位置
    old_food = *food;

    // 显示得分提示
    score_and_tips(0, high_score, 1);
    // 显示操作提示
    print_tips();
}

void move_snake(Snake *snake) {
    // 移动蛇身
    for (int i = snake->length - 1; i > 0; i--) {
        snake->x[i] = snake->x[i - 1];
        snake->y[i] = snake->y[i - 1];
    }

    // 根据方向移动蛇头
    switch (snake->dir) {
        case LEFT:
            snake->x[0]--;
            break;
        case RIGHT:
            snake->x[0]++;
            break;
        case UP:
            snake->y[0]--;
            break;
        case DOWN:
            snake->y[0]++;
            break;
    }
}

void update_snake(Snake *snake, int growing) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    // 清除旧蛇尾 (如果没有增长)
    if (!growing) {
        gotoxy(last_tail_x, last_tail_y);
        printf(" ");
    }

    // 绘制新蛇头
    gotoxy(snake->x[0], snake->y[0]);
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN);
    printf("O");
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

    // 绘制蛇身 (从第二节开始)
    for (int i = 1; i < snake->length; i++) {
        gotoxy(snake->x[i], snake->y[i]);
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN);
        printf("o");
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    }
}

void update_food(Food *food) {
    // 如果食物位置发生变化，更新食物
    if (food->x != old_food.x || food->y != old_food.y) {
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        gotoxy(old_food.x, old_food.y);
        printf(" ");  // 清除旧食物
        gotoxy(food->x, food->y);
        SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN);
        printf("$");
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    }
}

void update_score(int score, int high_score, int speed_level) {
    // 仅更新得分那一行
    gotoxy(0, HEIGHT + 1);
    printf("当前得分: %d   历史最高分: %d     ", score, high_score);
    gotoxy(0, HEIGHT + 2);
    printf("速度等级: %d                   ", speed_level);
}

void generate_food(Snake *snake, Food *food) {
    int valid;
    do {
        valid = 1;
        food->x = rand() % (WIDTH - 2) + 1;
        food->y = rand() % (HEIGHT - 2) + 1;
        
        // 确保食物不会出现在蛇身上
        for (int i = 0; i < snake->length; i++) {
            if (food->x == snake->x[i] && food->y == snake->y[i]) {
                valid = 0;
                break;
            }
        }
    } while (!valid);
}

int check_collision(Snake *snake) {
    // 检查是否撞墙
    if (snake->x[0] <= 0 || snake->x[0] >= WIDTH - 1 ||
        snake->y[0] <= 0 || snake->y[0] >= HEIGHT - 1)
        return 1;

    // 检查是否撞到自己 (从第4节开始检查，避免误判)
    for (int i = 4; i < snake->length; i++) {
        if (snake->x[0] == snake->x[i] && snake->y[0] == snake->y[i])
            return 1;
    }

    return 0;
}

void save_score(int score) {
    FILE *file = fopen("highscore.txt", "w");
    if (file != NULL) {
        fprintf(file, "%d", score);
        fclose(file);
    }
}

int load_score() {
    int score = 0;
    FILE *file = fopen("highscore.txt", "r");
    if (file != NULL) {
        fscanf(file, "%d", &score);
        fclose(file);
    }
    return score;
}

void game_over_screen(int score, int high_score, int *restart) {
    int choice;
    while (1) {
        // 使用局部刷新策略，避免清屏
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);

        // 清空屏幕以避免残留
        system("cls");

        print_GAMEOVER();
        printf("最终得分: %d\n", score);

        if (score < high_score) {
            printf("继续努力吧~你离最高分还差: %d 分\n", high_score - score);
        } else {
            printf("创纪录啦！最高分被你刷新啦，真棒！！！\n");
        }

        printf("\n1. 重玩\n2. 退出游戏\n");
        choice = _getch() - '0';

        switch (choice) {
            case 1:
                *restart = 1;
                return;
            case 2:
                *restart = 0;
                return;
            default:
                printf("输入错误，请重新选择...\n");
                Sleep(1000);
                break;
        }
    }
}

void explanation() {
    system("cls");
    printf("游戏说明：\n");
    printf("1. 使用 'WASD' 控制蛇的移动方向。\n");
    printf("2.按 上箭头 键加速，按 下箭头 键减速。\n");
    printf("3.吃到食物后总得分以速度等级为单位增加。\n");
    printf("4. 蛇撞到墙或咬到自己会导致游戏失败。\n");
    printf("5. 按 ESC 键暂停游戏。\n");
    printf("\n按任意键返回主菜单...");
    _getch();
}

void welcome_to_game() {
    int choice;
    while (1) {
        system("cls");
        print_snake();
        printf("\n");
        printf("1. 开始游戏\n");
        printf("2. 游戏说明\n");
        printf("3. 退出游戏\n");
        printf("请选择: ");
        choice = _getch() - '0';

        switch (choice) {
            case 1:
                return;
            case 2:
                explanation();
                break;
            case 3:
                exit(0);
            default:
                printf("无效的选择。按任意键继续...");
                _getch();
                break;
        }
    }
}

void print_GAMEOVER() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);

    printf(" _____   ___  ___  ___ _____ _____  _   _ ___________   _ _ _ \n");
    printf("|  __ \\ / _ \\ |  \\/  ||  ___|  _  || | | |  ___| ___ \\ | | | |\n");
    printf("| |  \\/| /_\\ \\| .  . || |__ | | | || | | | |__ | |_/ / | | | |\n");
    printf("| | __ |  _  || |\\/| ||  __|| | | || | | |  __||    /  | | | |\n");
    printf("| |_\\ \\| | | || |  | || |___\\ \\_/ / \\ \\/ / |___| |\\ \\  |_|_|_|\n");
    printf(" \\____/\\_| |_/\\_|  |_/\\____/ \\___/   \\__/|____/\\_| \\_\\ (_|_|_)\n");

    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}

void print_snake() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_INTENSITY);

    printf(" _____                   _       _____                     \n");
    printf("|  __ \\                 | |     /  ___|            _   \n");
    printf("| |  \\/_ __ ___  ___  __| |_   _\\`--. _ ___   __ _| | _____ \n");
    printf("| | __| '__/ _ \\/ _ \\/ _` | | | |`--. \\ '_ \\ / _` | |/ / _ \\ \n");
    printf("| |_\\ \\ | |  __/  __/ (_| | |_| /\\__/ / | | | (_| |   <  __/ \n");
    printf(" \\____/_|  \\___|\\___|\\__,_|\\__, \\____/|_| |_|\\__,_|_|\\_\\___| \n");
    printf("                            __/ |                           \n");
    printf("                           |___/                            \n");

    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}

void score_and_tips(int score, int high_score, int speed_level) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    gotoxy(0, HEIGHT + 1);
    printf("当前得分: %d   历史最高分: %d     ", score, high_score);
    gotoxy(0, HEIGHT + 2);
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
    printf("速度等级: %d                   ", speed_level);
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}

void speedup(int *sleeptime, int *speed_level) {
    if (*sleeptime > 30) {
        *sleeptime -= 30;
        if(*speed_level < 5) (*speed_level)++;
    }
}

void speeddown(int *sleeptime, int *speed_level) {
    if (*sleeptime < 270) {
        *sleeptime += 30;
        if(*speed_level > 1) (*speed_level)--;
    }
}

void keyboardControl(Snake *snake, int *sleeptime, int *score, int *paused, int *speed_level) {
    if (_kbhit()) {
        int key = _getch();

        if (key == 0 || key == 0xE0) {
            key = _getch();

            switch (key) {
                case 72: speedup(sleeptime, speed_level); break;
                case 80: speeddown(sleeptime, speed_level); break;
                case 75: if (snake->dir != RIGHT) snake->dir = LEFT; break;
                case 77: if (snake->dir != LEFT) snake->dir = RIGHT; break;
                
            }
        } else {
            switch (key) {
                case 'a': if (snake->dir != RIGHT) snake->dir = LEFT; break;
                case 'd': if (snake->dir != LEFT) snake->dir = RIGHT; break;
                case 'w': if (snake->dir != DOWN) snake->dir = UP; break;
                case 's': if (snake->dir != UP) snake->dir = DOWN; break;
                case 27: *paused = !(*paused); break; // 切换暂停状态
            }
        }
    }
}



